﻿#pragma once

#include <tuple>
#include <string>
#include <functional>
#include <map>
#include <type_traits>
#include <iostream>

class IPlugin;

// 类型萃取模板
template <typename T>
struct function_traits;

template <typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...)>
{
  using args_type = std::tuple<Args...>;
  using return_type = R;
  static constexpr size_t arity = sizeof...(Args);
};

// 参数打包/解包工具
struct ParamPacker
{
  template <typename... Args>
  static std::vector<uint8_t> Pack(Args &&...args)
  {
    std::vector<uint8_t> buffer;
    (PackSingle(buffer, std::forward<Args>(args)), ...);
    return buffer;
  }

  template <typename T>
  static T UnpackSingle(const std::vector<uint8_t> &buffer)
  {
    if (buffer.size() != sizeof(T))
    {
      throw std::runtime_error("Parameter size mismatch");
    }
    T value;
    memcpy(&value, buffer.data(), sizeof(T));
    return value;
  }

  template <typename Tuple>
  static auto Unpack(const std::vector<uint8_t> &buffer)
  {
    if constexpr (is_tuple_v<Tuple>)
    {
      size_t offset = 0;
      return UnpackImpl<Tuple>(buffer, offset, std::make_index_sequence<std::tuple_size_v<Tuple>>{});
    }
    else
    {
      return UnpackSingle<Tuple>(buffer);
    }
  }

private:
  template <typename T>
  static void PackSingle(std::vector<uint8_t> &buffer, T &&value)
  {
    auto *ptr = reinterpret_cast<uint8_t *>(&value);
    buffer.insert(buffer.end(), ptr, ptr + sizeof(T));
  }

  template <typename Tuple, size_t... I>
  static Tuple UnpackImpl(const std::vector<uint8_t> &buffer, size_t &offset, std::index_sequence<I...>)
  {
    return Tuple{(UnpackSingle<std::tuple_element_t<I, Tuple>>(buffer, offset))...};
  }

  template <typename T>
  static T UnpackSingle(const std::vector<uint8_t> &buffer, size_t &offset)
  {
    T value;
    memcpy(&value, buffer.data() + offset, sizeof(T));
    offset += sizeof(T);
    return value;
  }

  template <typename T>
  static constexpr bool is_tuple_v = false;

  template <typename... Ts>
  static constexpr bool is_tuple_v<std::tuple<Ts...>> = true;
};

template <typename PluginType, typename Func>
struct Invoker
{
  using Trait = function_traits<Func>;
  using Args = typename Trait::args_type;
  using Result = typename Trait::return_type;

  static inline std::vector<uint8_t>
  Apply(PluginType *plugin, Func func, const std::vector<uint8_t> &params)
  {
    if constexpr (std::is_same_v<Result, void>)
    {
      // 处理void返回值
      ApplyImpl(plugin, func, params);
      return {}; // 返回空数据表示void
    }
    else
    {
      // 处理非void返回值
      auto result = ApplyImpl(plugin, func, params);
      return ParamPacker::Pack(result);
    }
  }

private:
  template <typename R = Result>
  static auto ApplyImpl(PluginType *plugin, Func func, const std::vector<uint8_t> &params)
  {
    if constexpr (Trait::arity == 0)
    {
      if constexpr (!std::is_same_v<R, void>)
      {
        return (plugin->*func)();
      }
      else
      {
        (plugin->*func)();
      }
    }
    else
    {
      if (params.size() != sizeof(Args))
      {
        throw std::runtime_error("Parameter size mismatch");
      }

      auto args = ParamPacker::Unpack<Args>(params);
      return std::apply(
          [plugin, func](auto &&...args)
          {
            if constexpr (!std::is_same_v<R, void>)
            {
              return (plugin->*func)(std::forward<decltype(args)>(args)...);
            }
            else
            {
              (plugin->*func)(std::forward<decltype(args)>(args)...);
            }
          },
          args);
    }
  }
};

struct CallableContainer
{
  template <typename PluginType, typename Func>
  void RegisterCallable(PluginType *plugin, const std::string &funcName, Func func)
  {
    auto name = plugin->GetName() + "." + funcName;
    fnMap[name] = [plugin, func](const std::vector<uint8_t> &params)
    {
      return Invoker<PluginType, Func>::Apply(plugin, func, params);
    };
  }

  std::map<std::string, std::function<std::vector<uint8_t>(const std::vector<uint8_t> &)>> fnMap;
};